package controllers

import (
	"context"
	"fmt"

	"gitee.com/lishixi/gops/book/config"
	"gitee.com/lishixi/gops/book/exception"
	"gitee.com/lishixi/gops/book/models"
	"github.com/rs/zerolog"
	"gorm.io/gorm"
)

func NewBookController() *BookController {
	return &BookController{
		db:     config.Get().MySQL.DB(),
		logger: config.Get().Log.Logger(),
	}
}

type BookController struct {
	db     *gorm.DB
	logger *zerolog.Logger
}

type GetBookRequest struct {
	Isbn int64
}

// 怎么定于 book controller 接口
// 函数名 + 参数 + 返回 + 异常
// 考虑兼容性，元素个数不能变
// 一般会创建一个参数的 struct ，有变更可以直接变更结构体，这里是 GetBookRequest
// 传入 context 作为参数，方便扩展
// 1. 非功能性需求，traceId 、请求取消
// go context.Context 既能存储数据，也支持 Gorutine 取消
func (c *BookController) GetBook(ctx context.Context, req *GetBookRequest) (*models.Book, error) {
	ins := &models.Book{}
	// id := ctx.Param("isbn")
	if err := c.db.WithContext(ctx).Where("isbn = ?", req.Isbn).Take(&ins).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, exception.ErrorNotFound("%d Not Found", req.Isbn)
		}
		return nil, fmt.Errorf("get book error %s", err)
	}
	return ins, nil
}

func (c *BookController) GetBookList(ctx context.Context) ([]models.Book, error) {
	// ins := &models.Book{}
	// id := ctx.Param("isbn")
	var books []models.Book
	if err := c.db.Find(&books).Error; err != nil {
		return nil, err
	}
	return books, nil
}

func (c *BookController) CreateBook(ctx context.Context, req *models.BookSpec) (*models.Book, error) {
	// 校验
	if err := req.Validate(); err != nil {
		return nil, err
	}

	c.logger.Debug().Msgf("req 请求信息: %s", req)
	// book, save
	ins := &models.Book{
		BookSpec: *req,
	}
	if err := c.db.Save(ins).Error; err != nil {
		return nil, err
	}

	return ins, nil
}

func (c *BookController) UpdateBook(ctx context.Context, id *GetBookRequest, req *models.BookSpec) (*models.Book, error) {
	ins := &models.Book{
		BookSpec: *req,
	}

	// gorm更新是，如果字段为零值 就不更新该字段, is_sale 没办法更新为false
	// 如果越到零值，也需要更新，则需要转化为指针类型
	if err := c.db.Where("isbn = ?", id.Isbn).Model(&models.Book{}).Updates(ins).Error; err != nil {
		return nil, err
	}
	return ins, nil

}

func (c *BookController) DeleteBook(ctx context.Context, req *GetBookRequest) error {

	id := req.Isbn
	if err := c.db.Where("isbn = ?", id).Delete(&models.Book{}).Error; err != nil {
		return err
	}
	return nil
}
